package com.zz.framework.core.ext

import com.zz.framework.core.utils.*
import java.io.File
import java.math.BigDecimal
import java.nio.charset.Charset


val File.canListFiles: Boolean
    get() = canRead() and isDirectory

/**
 * Total size (include all subFile)
 */
val File.totalSize: Long
    get() = if (isFile) length() else getFolderSize(this)

/**
 * Formatted total size (include all subFile)
 */
val File.formatSize: String
    get() = getFormatFileSize(totalSize)

/**
 * Return file's mimeType, such as "png"
 */
val File.mimeType: String
    get() = getMimeType(extension, isDirectory)

/**
 * List sub files
 * @param isRecursive whether to list recursively
 * @param filter exclude some files
 */
fun File.listFiles(
    isRecursive: Boolean = false,
    filter: ((file: File) -> Boolean)? = null
): Array<out File> {
    val fileList = if (!isRecursive) listFiles() else getAllSubFile(this)
    var result: Array<File> = arrayOf()
    return if (filter == null) fileList
    else {
        for (file in fileList) {
            if (filter(file)) result = result.plus(file)
        }
        result
    }
}

/**
 * write some text to file
 * @param append whether to append or overwrite
 * @param charset default charset is utf-8
 */
fun File.writeText(append: Boolean = false, text: String, charset: Charset = Charsets.UTF_8) {
    if (append) appendText(text, charset) else writeText(text, charset)
}

/**
 * write some bytes to file
 * @param append whether to append or overwrite
 */
fun File.writeBytes(append: Boolean = false, bytes: ByteArray) {
    if (append) appendBytes(bytes) else writeBytes(bytes)
}

/**
 *  copy file
 *  @param destFile dest file/folder
 *  @param overwrite whether to override dest file/folder if exist
 *  @param reserve Whether to reserve source file/folder
 */
fun File.moveTo(destFile: File, overwrite: Boolean = true, reserve: Boolean = true): Boolean {
    val dest = copyRecursively(destFile, overwrite)
    if (!reserve) deleteRecursively()
    return dest
}

/**
 * copy file with progress callback
 * @param destFolder dest folder
 * @param overwrite whether to override dest file/folder if exist
 * @param func progress callback (from 0 to 100)
 */
fun File.moveToWithProgress(
    destFolder: File,
    overwrite: Boolean = true,
    reserve: Boolean = true,
    func: ((file: File, i: Int) -> Unit)? = null
) {

    if (isDirectory) copyFolder(this, File(destFolder, name), overwrite, func)
    else copyFile(this, File(destFolder, name), overwrite, func)

    if (!reserve) deleteRecursively()
}

/** Rename to newName */
fun File.rename(newName: String) =
    rename(File("$parent${File.separator}$newName"))

/** Rename to newFile's name */
fun File.rename(newFile: File) =
    if (newFile.exists()) false else renameTo(newFile)


fun Double.getFormatSize(): Pair<String, String> {
    val kiloByte: Double = this / 1024.0
    if (kiloByte < 1) {
        return Pair(this.toString(), "B")
    }
    val megaByte = kiloByte / 1024
    if (megaByte < 1) {
        val result1 = BigDecimal(java.lang.Double.toString(kiloByte))
        return Pair(result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "KB")
    }
    val gigaByte = megaByte / 1024
    if (gigaByte < 1) {
        val result2 = BigDecimal(java.lang.Double.toString(megaByte))
        return Pair(result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "MB")
    }
    val teraBytes = gigaByte / 1024
    if (teraBytes < 1) {
        val result3 = BigDecimal(java.lang.Double.toString(gigaByte))
        return Pair(result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "GB")
    }
    val result4 = BigDecimal(teraBytes)
    return Pair(result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "TB")
}

fun Long.getFormatSize(): Pair<String, String> {
    val kiloByte:Double = this / 1024.0
    if (kiloByte < 1) {
        return Pair(this.toString(), "B")
    }
    val megaByte = kiloByte / 1024.0
    if (megaByte < 1) {
        val result1 = BigDecimal(java.lang.Double.toString(kiloByte))
        return Pair(result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "KB")
    }
    val gigaByte = megaByte / 1024.0
    if (gigaByte < 1) {
        val result2 = BigDecimal(java.lang.Double.toString(megaByte))
        return Pair(result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "MB")
    }
    val teraBytes = gigaByte / 1024.0
    if (teraBytes < 1) {
        val result3 = BigDecimal(java.lang.Double.toString(gigaByte))
        return Pair(result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "GB")
    }
    val result4 = BigDecimal(teraBytes)
    return Pair(result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "TB")
}

fun Long.getFormatFileSize(): Pair<String, String> {
    val kiloByte: Double = this / 1024.0
    if (kiloByte < 1) {
        return Pair(this.toString(), "B")
    }
    val megaByte = kiloByte / 1024.0
    if (megaByte < 1) {
        val result1 = BigDecimal(java.lang.Double.toString(kiloByte))
        return Pair(result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "KB")
    }
    val gigaByte = megaByte / 1024.0
    if (gigaByte < 1) {
        val result2 = BigDecimal(java.lang.Double.toString(megaByte))
        return Pair(result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "MB")
    }
    val teraBytes = gigaByte / 1024.0
    if (teraBytes < 1) {
        val result3 = BigDecimal(java.lang.Double.toString(gigaByte))
        return Pair(result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "GB")
    }
    val result4 = BigDecimal(teraBytes)
    return Pair(result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "TB")
}
fun Long.getFormatFileSize2(): Pair<String, String> {
    val kiloByte: Double = this / 1000.0
    if (kiloByte < 1) {
        return Pair(this.toString(), "B")
    }
    val megaByte = kiloByte / 1000.0
    if (megaByte < 1) {
        val result1 = BigDecimal(java.lang.Double.toString(kiloByte))
        return Pair(result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "KB")
    }
    val gigaByte = megaByte / 1000.0
    if (gigaByte < 1) {
        val result2 = BigDecimal(java.lang.Double.toString(megaByte))
        return Pair(result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "MB")
    }
    val teraBytes = gigaByte / 1000.0
    if (teraBytes < 1) {
        val result3 = BigDecimal(java.lang.Double.toString(gigaByte))
        return Pair(result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "GB")
    }
    val result4 = BigDecimal(teraBytes)
    return Pair(result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(), "TB")
}


fun String?.getSuffix(): String {
    if (this?.lastIndexOf(".") != -1 && this?.lastIndexOf(".") != 0)
        return this?.lastIndexOf(".")?.let { this?.substring(it)?.toLowerCase() } ?:""
    else return ""
}
fun String?.getSuffixWithoutDot(): String {
    if (this?.lastIndexOf(".") != -1 && this?.lastIndexOf(".") != 0)
        return this?.substring(this?.lastIndexOf(".")!!+1)?.toLowerCase()?:""
    else return ""
}

